package cn.heygod.graywhale.runtime.script;

import cn.heygod.graywhale.runtime.context.Input;
import cn.heygod.graywhale.runtime.context.Output;
import cn.heygod.graywhale.runtime.exception.ServiceException;
import cn.heygod.graywhale.runtime.script.domain.GwScriptRuntime;
import cn.heygod.graywhale.runtime.script.mapper.GwScriptRuntimeMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

@Service
public class JavaScriptService implements ScriptService{

    /**
     * 函数名
     */
    public static final String FUNCTION_NAME = "__run";


    public static final String ENGINE_NAME = "nashorn";

    @Autowired
    private GwScriptRuntimeMapper scriptMapper;

    @Override
    public Output run(String scriptId, Input input) {
        ScriptContent scriptContent = getScript(scriptId);
        //TODO 决策点，脚本外部的function体放到content内容，还是在运行时组装？选择运行时组装
        //1、运行时组装有性能损耗。但前端保存比较方便
        //2、保存时组装好，运行时更快。
        StringBuilder scriptBuilder = new StringBuilder();
        scriptBuilder.append(" function ").append(FUNCTION_NAME).append(" (input) { ");
        scriptBuilder.append(scriptContent.getContent());
        scriptBuilder.append("}");

        Output output = new Output();
        try {
            ScriptEngine engine = getScriptEngine();
            engine.eval(scriptBuilder.toString());
            Invocable jsInvoke = (Invocable) engine;
            //java中调用js

            Object result = jsInvoke.invokeFunction(FUNCTION_NAME, input.getBody());
            output.setBody(result);
            return output;
        } catch (ScriptException e) {
            output.error(e);
        } catch (NoSuchMethodException e) {
            output.error(e);
        }
        return output;
    }

    private ScriptEngine getScriptEngine(){
        ScriptEngineManager sem = new ScriptEngineManager();
        ScriptEngine engine = sem.getEngineByName(ENGINE_NAME);
        return engine;
    }

    @Override
    public ScriptContent getScript(String scriptId) {
        //考虑加缓存
        GwScriptRuntime gwScript =  scriptMapper.selectById(scriptId);
        if(gwScript == null){
            throw new ServiceException("没有找到相应的脚本");
        }
        ScriptContent scriptContent = new ScriptContent();
        scriptContent.setScriptId(gwScript.getId());
        scriptContent.setContent(gwScript.getScriptContent());
        scriptContent.setType(ScriptContent.JAVASCRIPT);
        return scriptContent;
    }
}
